/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.misc.dts.oo.util;

import com.sun.star.beans.PropertyValue;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.CloseVetoException;
import com.sun.star.util.XCloseable;
import org.vacoor.nothing.common.misc.util.Platform;

import java.io.File;
import java.io.FilenameFilter;
import java.net.URL;

/**
 * @author vacoor
 */
public abstract class UnoUtils {
    /**
     * 根据给定的键值构建 PropertyValue
     *
     * @param name
     * @param value
     * @return
     */
    public static PropertyValue of(String name, Object value) {
        PropertyValue pv = new PropertyValue();
        pv.Name = name;
        pv.Value = value;
        return pv;
    }

    public static PropertyValue[] of(PropertyValue... pvs) {
        return pvs;
    }

    public static PropertyValue[] of(String k1, Object v1, String k2, Object v2) {
        return of(of(k1, v1), of(k2, v2));
    }

    public static PropertyValue[] of(String k1, Object v1, String k2, Object v2, String k3, Object v3) {
        return of(of(k1, v1), of(k2, v2), of(k3, v3));
    }

    public static PropertyValue[] of(String k1, Object v1, String k2, Object v2, String k3, Object v3, String k4, Object v4) {
        return of(of(k1, v1), of(k2, v2), of(k3, v3), of(k4, v4));
    }

    public static PropertyValue[] of(PropertyValue[] pvs1, PropertyValue... pvs2) {
        PropertyValue[] pvs = new PropertyValue[pvs1.length + pvs2.length];
        for (int i = 0; i < pvs1.length; i++) {
            pvs[i] = pvs1[i];
        }
        for (int i = 0; i < pvs2.length; i++) {
            pvs[pvs1.length + i] = pvs2[i];
        }
        return pvs;
    }

    public static String toUrl(URL url) {
        return "file://" + url.getFile();
    }

    /**
     * 当 {@link com.sun.star.uno.UnoRuntime#queryInterface} 可以将 xComp 转换为 XCloseable
     * 并且成功调用 disconnect 时返回 true, 其余情况返回false
     *
     * @param xComp
     * @return
     */
    public static boolean closeIf(Object xComp) {
        XCloseable xCloseable = UnoRuntime.queryInterface(XCloseable.class, xComp);
        if (xCloseable != null) {
            try {
                xCloseable.close(true);
                return true;
            } catch (CloseVetoException ignore) {
                // ignore
            }
        }
        return false;
    }

    /**
     * 当 {@link com.sun.star.uno.UnoRuntime#queryInterface} 可以将 xComp 转换为 XComponent
     * 并且成功调用 dispose 时返回 true, 其余情况返回false
     *
     * @param xComp
     * @return
     */
    public static boolean disposeIf(Object xComp) {
        XComponent xComponent = $(XComponent.class, xComp);
        if (xComponent != null) {
            xComponent.dispose();
            return true;
        }
        return false;
    }

    /**
     * 使用给定上下文和名称创建给定类型的组件
     *
     * @param ctx
     * @param type
     * @param cmpName
     * @param <T>
     * @return
     * @throws com.sun.star.uno.Exception
     */
    public static <T> T $(XComponentContext ctx, Class<T> type, String cmpName) throws Exception {
        return $(type, $(ctx, cmpName));
    }

    /**
     * 使用给定的 XComponentContext 创建给定名称的组件
     *
     * @param ctx
     * @param cmpName
     * @return
     * @throws com.sun.star.uno.Exception
     */
    public static Object $(XComponentContext ctx, String cmpName) throws Exception {
        XMultiComponentFactory xMultiCmpFactory = ctx.getServiceManager();
        return xMultiCmpFactory.createInstanceWithContext(cmpName, ctx);
    }

    /**
     * UnoRuntime.queryInterface
     *
     * @param type
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> T $(Class<T> type, Object obj) {
        return (T) UnoRuntime.queryInterface(type, obj);
    }

    /**
     * get soffice absolute path
     * <p/>
     * mac os x: $OO_HOME/MacOS/soffice
     * windows: $OO_HOME/program/soffice.exe
     * linux and other: $OO_HOME/program/soffice.bin
     *
     * @param ooHome OO_HOME
     * @return
     */
    public static String getSoffice(String ooHome) {
        if (ooHome == null) {
            return null;
        }

        String relative = "program/soffice";

        if (Platform.isMac()) {
            relative = "MacOS/soffice";
        } else if (Platform.isWindows()) {
            relative = "program/soffice.exe";
        }
        return new File(ooHome, relative).getAbsolutePath();
    }

    /**
     * find OO_HOME from generic install directory
     * <p/>
     * mac os x: "/Applications" and "$HOME/Applications", ( OO_HOME is OO_APP/Contents )
     * linux:   "/opt" and "/usr/lib"
     * windows: "%ProgramFiles%" and "%ProgramFiles(x86)%"
     *
     * @return
     */
    public static String findOOHome() {
        String ooHome = System.getenv("OO_HOME");
        if (ooHome == null) {
            ooHome = System.getProperty("oo.home");
        }
        if (ooHome != null) {
            return ooHome;
        }

        if (Platform.isWindows()) {
            return findOODirectory(
                    System.getenv("ProgramFiles"),
                    System.getenv("ProgramFiles(x86)")
            );
        }
        if (Platform.isMac()) {
            ooHome = findOODirectory(
                    "/Applications",
                    System.getProperty("user.home") + "/Applications"
            );
            return ooHome != null ? ooHome + "/Contents" : null;
        }
        if (Platform.isLinux()) {
            return findOODirectory(
                    "/opt",
                    "/usr/lib",
                    "/usr/lib64"
            );
        }
        return null;
    }

    /**
     * find starts width "openoffice" or "libreoffice" dir in given directories
     *
     * @param searchDirs search dirs
     * @return starts with "openoffice" or "libreoffice" dir
     */
    private static String findOODirectory(String... searchDirs) {
        for (String d : searchDirs) {
            if (d == null || d.length() == 0) {
                continue;
            }
            File dir = new File(d);
            if (!dir.isDirectory()) {
                continue;
            }

            File[] files = dir.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    name = name.toLowerCase();
                    return name.startsWith("libreoffice") || name.startsWith("openoffice");
                }
            });

            if (files != null && files.length > 0) {
                return files[0].getAbsolutePath();
            }
        }

        return null;
    }

    public static String getFileExtension(String filename) {
        if (filename == null) {
            return null;
        }
        int pos = indexOfFileExtension(filename);
        return pos < 0 ? "" : filename.substring(pos + 1);
    }

    public static int indexOfFileExtension(String filename) {
        if (filename == null) {
            return -1;
        }
        filename = filename.replace('\\', '/');
        int sepPos = filename.lastIndexOf('/');
        int dotPos = filename.lastIndexOf('.');
        return dotPos > sepPos ? dotPos : -1;
    }

    private UnoUtils() {
    }
}
